home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Online / HBBS / Source / Node / Node_Input.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  67KB  |  2,359 lines

  1. /*
  2.  
  3.    Node_Input.c - written By Dominic Clifton, part of HydraBBS's Node program
  4.  
  5.    (C) 1994-7 Dominic Clifton - Hydra/dAT - Deluxe Software
  6.  
  7.  
  8.    Primarly the code for checking input from the user/sysop and
  9.    handles door<->node communications.
  10.  
  11. */
  12.  
  13. #define USE_BUILTIN_MATH
  14. #include <string.h>
  15. #include <math.h>
  16. #include <stdio.h>
  17. #include <exec/types.h>
  18. #include <libraries/locale.h>
  19. #include <exec/memory.h>
  20. #include <dos/dosextens.h>
  21. #include <intuition/screens.h>
  22. #include <intuition/intuition.h>
  23. #include <intuition/gadgetclass.h>
  24. #include <libraries/gadtools.h>
  25. #include <diskfont/diskfont.h>
  26. #include <utility/utility.h>
  27. #include <graphics/gfxbase.h>
  28. #include <devices/console.h>
  29. #include <workbench/workbench.h>
  30. #include <graphics/scale.h>
  31. #include <clib/locale_protos.h>
  32. #include <clib/exec_protos.h>
  33. #include <clib/wb_protos.h>
  34. #include <clib/intuition_protos.h>
  35. #include <clib/gadtools_protos.h>
  36. #include <clib/graphics_protos.h>
  37. #include <clib/utility_protos.h>
  38. #include <clib/diskfont_protos.h>
  39.  
  40. #include <dos/dos.h>
  41. #include <dos/dostags.h>
  42. #include <stdlib.h>
  43. #include <stdio.h>
  44. #include <ctype.h>
  45. #include <time.h>
  46. #include <libraries/reqtools.h>
  47.  
  48. #include <clib/alib_protos.h>
  49. #include <clib/dos_protos.h>
  50. #include <clib/reqtools_protos.h>
  51.  
  52. #include "NodeGUI.h"
  53.  
  54. #define ClrSignal(s)  SetSignal(0,s)
  55.  
  56. extern struct ReqToolsBase *ReqToolsBase;
  57. extern ULONG InfoWinActive;
  58. extern ULONG *rttags;
  59.  
  60. #include <hbbs/types.h>
  61. #include <hbbs/errors.h>
  62. #include <hbbs/access.h>
  63. #include <hbbs/defines.h>
  64. #include <hbbs/structures.h>
  65. #include <hbbs/strings.h>
  66. #include <hbbs/files.h>
  67. #include <hbbs/ansi_codes.h>
  68.  
  69. #include <HBBS/Hbbscommon_protos.h>
  70. #ifdef __SASC
  71. #include <HBBS/hbbscommon_pragmas_sas.h>
  72. #else
  73. #include <HBBS/hbbscommon_pragmas_stc.h>
  74. #endif
  75.  
  76. #include <HBBS/Hbbsnode_protos.h>
  77. #ifdef __SASC
  78. #include <HBBS/Hbbsnode_pragmas_sas.h>
  79. #else
  80. #include <HBBS/Hbbsnode_pragmas_stc.h>
  81. #endif
  82.  
  83. //#include "Node_Console_Protos.h"
  84. #include "Node_Serial_Protos.h"
  85. #include "Node_Main_Protos.h"
  86. #include "Node_Misc_Protos.h"
  87. #include "Node_Input_Protos.h"
  88.  
  89. extern int N_NodeNum;
  90. extern struct BBSGlobalData *BBSGlobal;
  91. extern struct NodeData *N_ND;
  92. extern struct Library *HBBSCommonBase;
  93. extern struct Library *HBBSNodeBase;
  94. extern struct List *HistoryList;
  95. extern ULONG HistoryItems;
  96.  
  97. #include "/common/shared_protos.h"
  98.  
  99. void SetUpSigs( void )
  100. {
  101.   // this routine sets up all the signals availiable so you can checksignal() them
  102.   // or wait() on them or whatever....
  103.  
  104.  
  105.   if (N_ND->NodeSettings.Iconified==FALSE)
  106.     N_ND->WinSig=DEF_WINSIG;
  107.   else
  108.     N_ND->WinSig=0L;
  109.  
  110.   if (N_ND->InformationOpen)
  111.     N_ND->InfoWinSig=DEF_INFOWINSIG;
  112.   else
  113.     N_ND->InfoWinSig=0L;
  114.  
  115.   if (N_ND->SettingsOpen)
  116.     N_ND->SettingsWinSig=DEF_SETTINGSWINSIG;
  117.   else
  118.     N_ND->SettingsWinSig=0L;
  119.  
  120.   SetupConSerSigs();
  121.  
  122.   N_ND->PortSig=DEF_PORTSIG;
  123.   N_ND->TimerSig=DEF_TIMERSIG;
  124. }
  125.  
  126. void SetUpDoorSigs( void )
  127. {
  128.   // this routine sets up all the signals availiable so you can checksignal() them
  129.   // or wait() on them or whatever....
  130.  
  131.   if (N_ND->NodeSettings.Iconified==FALSE)
  132.     N_ND->WinSig=DEF_WINSIG;
  133.   else
  134.     N_ND->WinSig=0L;
  135.  
  136.   if (N_ND->InformationOpen)
  137.     N_ND->InfoWinSig=DEF_INFOWINSIG;
  138.   else
  139.     N_ND->InfoWinSig=0L;
  140.  
  141.   if (N_ND->SettingsOpen)
  142.     N_ND->SettingsWinSig=DEF_SETTINGSWINSIG;
  143.   else
  144.     N_ND->SettingsWinSig=0L;
  145.  
  146.   N_ND->PortSig=DEF_PORTSIG;
  147.   N_ND->TimerSig=DEF_TIMERSIG;
  148. }
  149.  
  150.  
  151. void HandleMiscSigs( ULONG ReturnedSigs )
  152. {
  153.   // this routine handles all stuff like the sysop clicking on the node window
  154.   // or closing the watch screen etc. etc...
  155.  
  156.   ULONG class;
  157.   UWORD code;
  158.   struct Gadget *pgsel;
  159.   struct IntuiMessage *imsg;
  160.  
  161.   if (ReturnedSigs & N_ND->WinSig)
  162.   {
  163.     while ((NodeWnd) && (imsg=GT_GetIMsg(NodeWnd->UserPort)))
  164.     {
  165.       class=imsg->Class;
  166.       code=imsg->Code;
  167.       pgsel=(struct Gadget *)imsg->IAddress; /* Only reference if it is a gadget message */
  168.       GT_ReplyIMsg(imsg);
  169.       ProcessWindowNodeWnd(class, code, pgsel);
  170.     }
  171.   }
  172.  
  173.   if (ReturnedSigs & N_ND->ConWinSig)
  174.   {
  175.     while ((N_ND->ConWin) && (imsg=GT_GetIMsg(N_ND->ConWin->UserPort)))
  176.     {
  177.       class=imsg->Class;
  178.       code=imsg->Code;
  179.       pgsel=(struct Gadget *)imsg->IAddress; /* Only reference if it is a gadget message */
  180.       GT_ReplyIMsg(imsg);
  181.       ProcessConWindow(class, code, pgsel);
  182.     }
  183.   }
  184.  
  185.   if (ReturnedSigs & N_ND->InfoWinSig)
  186.   {
  187.     while ((InfoWin) && (imsg=GT_GetIMsg(InfoWin->UserPort)))
  188.     {
  189.       class=imsg->Class;
  190.       code=imsg->Code;
  191.       pgsel=(struct Gadget *)imsg->IAddress; /* Only reference if it is a gadget message */
  192.       GT_ReplyIMsg(imsg);
  193.       ProcessWindowInfoWin(class, code, pgsel);
  194.     }
  195.   }
  196.  
  197.   if (ReturnedSigs & N_ND->SettingsWinSig)
  198.   {
  199.     while ((SettingsWin) && (imsg=GT_GetIMsg(SettingsWin->UserPort)))
  200.     {
  201.       class=imsg->Class;
  202.       code=imsg->Code;
  203.       pgsel=(struct Gadget *)imsg->IAddress; /* Only reference if it is a gadget message */
  204.       GT_ReplyIMsg(imsg);
  205.       ProcessWindowSettingsWin(class, code, pgsel);
  206.     }
  207.   }
  208.  
  209.   if (ReturnedSigs & N_ND->PortSig)
  210.   {
  211.     HandleMsg(); // node can only be closed by a message from the CONTROL program
  212.   }
  213.  
  214.   if (ReturnedSigs & (1L << N_ND->OLMPort->mp_SigBit))
  215.   {
  216.     struct Message *Msg;
  217.  
  218.     while (Msg=GetMsg(N_ND->OLMPort))
  219.     {
  220.       FreeVec(Msg);
  221.     }
  222.   }
  223. }
  224.  
  225. ULONG WaitAllSigs(void)
  226. {
  227.   return(Wait((1L << N_ND->OLMPort->mp_SigBit) | N_ND->SettingsWinSig | N_ND->InfoWinSig |N_ND->WinSig | N_ND->PortSig | N_ND->ConSig | N_ND->SerSig | N_ND->ConWinSig | N_ND->TimerSig));
  228. }
  229.  
  230.  
  231. #define KEY_NONE 0
  232. #define KEY_ESCAPE 1
  233. #define KEY_CSI 2
  234.  
  235. ULONG CheckCSI(UBYTE ch,ULONG wherefrom)
  236. {
  237.   ULONG ReturnedSigs;
  238.   BOOL done=FALSE;
  239.   int csipos=0;
  240. //  int loop;
  241.  
  242.   if ((N_ND->char1==27 && ch=='[') || (ch==155))
  243.   {
  244.  
  245.     N_ND->char1=0;
  246.     while (!done)
  247.     {
  248.       // now, we have to be specific as to where we think the control sequence
  249.       // is coming from, for instance, say you had got the first byte of the
  250.       // control sequence from the serial port, you obviously wouldn't want
  251.       // any more of the control sequence coming from the console.. :-)
  252.  
  253.       if (wherefrom==GET_SERIAL)
  254.       {
  255.         if (!N_ND->SerWaiting) SendSerReadData();
  256.       }
  257.       if (wherefrom==GET_CONSOLE)
  258.       {
  259.         if (!N_ND->ConWaiting && N_ND->ConOK) ConReadData(1); // we only want to do a char at a time...
  260.       }
  261.       SetUpSigs();
  262.       ReturnedSigs=WaitAllSigs();
  263.       // handlemiscsigs() MAY close the console window.. so be careful!
  264.       // also N_ND->RequestShutdown MIGHT get set if the sysop clicks close
  265.       // on the control panel, BUT if we are in the middle of an escape sequence
  266.       // we don't want to know.
  267.       HandleMiscSigs(ReturnedSigs);
  268.  
  269.       while ( ((wherefrom==GET_SERIAL) && HandleSerSigs(ReturnedSigs)) ||
  270.               ((wherefrom==GET_CONSOLE) && HandleConSigs(ReturnedSigs)) )
  271.       {
  272.         if ( N_ND->IBuffer[0]>=0x40 && N_ND->IBuffer[0] <=0x7E)
  273.         {
  274.           N_ND->csistring[csipos]=N_ND->IBuffer[0];
  275.           csipos++;
  276.           done=TRUE;
  277.         }
  278.         else
  279.         {
  280.           N_ND->csistring[csipos]=N_ND->IBuffer[0];
  281.           csipos++;
  282.         }
  283.       }
  284.     }
  285.     N_ND->csistring[csipos]=0; // null terminate str..
  286.  
  287.     // note: csipos is same as doing strlen(N_ND->csistring)..
  288.  
  289.     return(KEY_CSI);
  290.  
  291.   }
  292.   else
  293.   {
  294.     if (ch==27)
  295.     {
  296.       N_ND->char1=27;
  297.       return(KEY_NONE);
  298.     }
  299.   }
  300.  
  301.   if (N_ND->char1==27)
  302.   {
  303.     N_ND->char1=0;
  304.     return(KEY_ESCAPE);
  305.   }
  306.   return(KEY_NONE);
  307. }
  308.  
  309. void handleescape( void )
  310. {
  311. //  puts("Escape Pressed!");
  312. }
  313.  
  314. // when writing data to the console or serial port we MUST use <ESC>[ and not 0x9B
  315. // cos then only amiga's would understand it! :-)  But hey! what a cool idea!
  316.  
  317. /* NOT USED ANYMORE!  only getline used them and I've had to modify that too much!
  318.   void CursorLeft( short num )
  319.   {
  320.     UBYTE outstr[6]; // csi+3digits+ansi terminator+null terminator
  321.     sprintf(outstr,"\033[%dD",num);
  322.     PutText(outstr);
  323.   }
  324.  
  325.   void CursorRight( short num )
  326.   {
  327.     UBYTE outstr[6]; // csi+3digits+ansi terminator+null terminator
  328.     sprintf(outstr,"\033[%dC",num);
  329.     PutText(outstr);
  330.   }
  331.  
  332.   void DeleteChars( short num )
  333.   {
  334.     UBYTE outstr[6]; // csi+3digits+ansi terminator+null terminator
  335.     sprintf(outstr,"\033[%dP",num);
  336.     PutText(outstr);
  337.   }
  338.  
  339.   void InsertChars( short num )
  340.   {
  341.     UBYTE outstr[6]; // csi+3digits+ansi terminator+null terminator
  342.     sprintf(outstr,"\033[%d@",num);
  343.     PutText(outstr);
  344.   }
  345. */
  346.  
  347. ULONG CheckFunctionKeys( void )
  348. {
  349.   // this routine checks the function keys, and depending on the
  350.   // N_ND->LoginType it does certain things...
  351.  
  352.   ULONG status=IN_NOTHING;
  353.  
  354. //  puts(N_ND->csistring);
  355.  
  356.   if (stricmp(N_ND->csistring,str_CSI_F7)==0)
  357.   {
  358.     HBBS_CleanupNodeConsoleWin();
  359.   }
  360.   else
  361.   if (stricmp(N_ND->csistring,str_CSI_F8)==0)
  362.   {
  363.     HBBS_ChangeConsoleMode(2); // swap between screen and window..
  364.     if ((N_ND->LoginType==LOGIN_NONE) && (N_ND->CurrentLine[0]==0)) status=IN_DISPLAYAWAIT;
  365.   }
  366.   else
  367.   if (N_ND->LoginType==LOGIN_NONE)
  368.   {
  369.     if (stricmp(N_ND->csistring,str_CSI_F1)==0) status=IN_LOGIN;      // Local Login
  370.     if (stricmp(N_ND->csistring,str_CSI_F2)==0)
  371.     {
  372.       InitModem();          // Init Modem
  373.     }
  374.     if (stricmp(N_ND->csistring,str_CSI_F3)==0) status=IN_IMMEDIATE;  // Answer Modem Now
  375.     if (stricmp(N_ND->csistring,str_CSI_F4)==0) status=IN_DISPLAYAWAIT; // re-display Awaitscreen
  376.     if (stricmp(N_ND->csistring,str_CSI_F5)==0)                       // toggle modem debug
  377.     {
  378.       N_ND->NodeDevice.ModemDebug=!N_ND->NodeDevice.ModemDebug;
  379.     }
  380.     if (stricmp(N_ND->csistring,str_CSI_F6)==0)
  381.     {
  382.       // we have to fool the system into thinking that there's someone
  383.       // logged in so that we can run the door! :-)
  384.       N_ND->LoginType=LOGIN_LOCAL;
  385.       N_ND->OnlineStatus=OS_ONLINE;
  386.  
  387.       GoSystemDoor("ACCOUNTEDIT",NULL);
  388.  
  389.       // but not forgetting to put it back to how it was..
  390.       N_ND->LoginType=LOGIN_NONE;
  391.       N_ND->OnlineStatus=OS_OFFLINE;
  392.  
  393.       // and display the await screen again to tidy up..
  394.       status=IN_DISPLAYAWAIT;
  395.     }
  396.     if (stricmp(N_ND->csistring,str_CSI_F9)==0) status=IN_TERMINAL;
  397.     if (stricmp(N_ND->csistring,str_CSI_SF9)==0) status=IN_DIALOUT;
  398.     if (stricmp(N_ND->csistring,str_CSI_F10)==0) status=IN_SHUTDOWN;
  399.   }
  400.   else // Oooh someone's logged in and the sysop wants to do something to the user!
  401.   {
  402.     if (stricmp(N_ND->csistring,str_CSI_F1)==0)
  403.     {
  404.       // chat door running ?
  405.       if ((N_ND->ActiveDoor) && (iposition("SYSOPCHAT",N_ND->ActiveDoor->node.ln_Name)>=0))
  406.       {
  407.         status=IN_ENDCHAT;
  408.       }
  409.       else
  410.       {
  411.         GoSystemDoor("SYSOPCHAT",NULL);
  412.         status=IN_ENDCHAT;
  413.       }
  414.     }
  415.     else
  416.     if (stricmp(N_ND->csistring,str_CSI_F6)==0)
  417.     {
  418.       if ((N_ND->ActiveDoor) && (iposition("ACCOUNTEDIT",N_ND->ActiveDoor->node.ln_Name)<0))
  419.       {
  420.         GoSystemDoor("ACCOUNTEDIT","SYSOPONLY");
  421.       }
  422.     }
  423.     else
  424.     if (stricmp(N_ND->csistring,str_CSI_SF6)==0)
  425.     {
  426.       if ((N_ND->ActiveDoor) && (iposition("ACCOUNTEDIT",N_ND->ActiveDoor->node.ln_Name)<0))
  427.       {
  428.         GoSystemDoor("ACCOUNTEDIT","SYSOPONLY CALLONLY");
  429.       }
  430.     }
  431.     else
  432.     if (stricmp(N_ND->csistring,str_CSI_SF10)==0)
  433.     {
  434.       if (N_ND->LoginType==LOGIN_REMOTE) HangUp();
  435.       return(IN_LOSSCARRIER);
  436.     }
  437.   }
  438.   return(status);
  439. }
  440. /*  see defines.h
  441.  
  442. #define GL_NONE      0  // default
  443. #define GL_HISTORY   1  // if set history is enabled (up/down cursor keys)
  444. #define GL_LINEWRAP  2  // if maxlen is reached then data back to the last ' ' character is copied to N_ND->CurrentLineWrap and returns immediately
  445. #define GL_IMMEDIATE 4  // returns when maxlen is reached
  446. #define GL_NORETURN  8  // does not print a cr+lf when a) reached maxlen or b) timeout or c) return press
  447. #define GL_EDIT      16 // enables cursor left/right and backspace/delete
  448. #define GL_DISPLAY   32 // display chars (don't specify for "Press [return] to contine" type prompts)
  449. #define GL_SYSOP     64 // does not write to, or read from, the serial port
  450. #define GL_USECHARS  128 // see N_ND->CharsAllowed
  451. #define GL_NOBEEP    256 // use with GL_USECHARS if you don't want a beep when
  452.                          // the presses a key not in N_ND->CharsAllowed
  453. #define GL_NOOLM     512 // (No OLM) if set olm's will not inturrpt the user
  454. #define GL_NODISTURB 1024// Lets you use things like "Enter ID: [    ]" with out the ] moving
  455. #define GL_CVTUPPER  2048// converts input chars to uppercase as the keys are pressed!
  456.  
  457. */
  458.  
  459. void ReDrawLine(ULONG Flags, int *xpos)
  460. {
  461.   char cmovestr[20];
  462.  
  463.   if (Flags & GL_DISPLAY)
  464.   {
  465.     // now move back to the start of the string and erase it,
  466.     // then print the new string
  467.  
  468.     if (*xpos)
  469.     {
  470.       sprintf(cmovestr,"\033[%dD",*xpos);
  471.     }
  472.     if (Flags & GL_SYSOP)
  473.     {
  474.       if (*xpos) PutConText(cmovestr);
  475.       PutConText("\033[K");
  476.       PutConText(N_ND->CurrentLine);
  477.     }
  478.     else
  479.     {
  480.       if (*xpos) PutText(cmovestr);
  481.       PutText("\033[K");
  482.       PutText(N_ND->CurrentLine);
  483.     }
  484.   }
  485.   *xpos=strlen(N_ND->CurrentLine);
  486. }
  487.  
  488.  
  489. V_BOOL CheckRaw(ULONG Flags)
  490. {
  491.   V_BOOL GotSomeData=FALSE;
  492.  
  493.   N_ND->CurrentLine[0]=0;
  494.   N_ND->CurrentLine[1]=0;
  495.   if (!(Flags & CR_NOCONSOLE) && (N_ND->ConOK))    // fixed, 25/07/96
  496.   {
  497.     if (N_ND->ConWaiting) AbortConRead();
  498.     N_ND->ConRead->io_Command  = CMD_READ;
  499.     N_ND->ConRead->io_Data     = (APTR)N_ND->CurrentLine;
  500.     N_ND->ConRead->io_Length   = 1;
  501.  
  502.     ClrSignal(1L << N_ND->ConRPort->mp_SigBit);
  503.     SendIO((struct IORequest*)N_ND->ConRead);
  504.  
  505.     if (CheckIO((struct IORequest*)N_ND->ConRead))
  506.     {
  507.       WaitIO((struct IORequest*)N_ND->ConRead);
  508.       if (N_ND->ConRead->io_Actual)
  509.       {
  510.         GotSomeData=TRUE;
  511.         N_ND->CurrentLine[2]=1;
  512.       }
  513.     }
  514.     else
  515.     {
  516.       AbortIO((struct IORequest*)N_ND->ConRead);
  517.     }
  518.   }
  519.   if (!((GotSomeData) || (Flags & CR_NOSERIAL)) && (N_ND->SerOK)) // fixed, 25/07/96
  520.   {
  521.     if (SerQueryData()>0)
  522.     {
  523.       WaitSerReadBlock(N_ND->CurrentLine,1);
  524.       GotSomeData=TRUE;
  525.       N_ND->CurrentLine[2]=2;
  526.     }
  527.   }
  528.   return((V_BOOL)GotSomeData);
  529. }
  530.  
  531. ULONG Get_Line(ULONG Flags,char PasswordChar,ULONG MaxLen, ULONG Timeout, UBYTE *PromptStr)
  532. {
  533.   char tmpstr[BIG_STR];
  534.   int editloop,editlen;
  535.   ULONG ReturnedSigs;
  536.   UBYTE CurrentChar[2]={0,0}; // 2 chars, use ¤tchar for null terminated string type..
  537.   int xpos=0;
  538.   ULONG csitype=0;
  539.   ULONG retval=IN_NOTHING; // this must NOT be returned to the caller!!!!!
  540.   struct TimerData *TD=NULL,    // TD is used if a timeout is specified
  541.                    *TO_TD=NULL, // used for Inactivity Disconnect
  542.                    *TL_TD=NULL; // used for time remaining
  543.  
  544.  
  545.   BOOL AddOK;
  546.   char *strptr;
  547.  
  548.   LONG HistoryNum=HistoryItems,OldHistNum=-1;
  549.   char cmovestr[20];
  550.  
  551.   if (N_ND->NodeFlags & NFLG_CTRLC) N_ND->NodeFlags-=NFLG_CTRLC;
  552.  
  553.  
  554.   N_ND->CurrentLine[0]=0; // null terminate the string..
  555.   N_ND->CurrentLineWrap[0]=0; // null terminate the string..
  556.  
  557.   if (MaxLen==0) MaxLen=LEN_CURRENTLINE;
  558.  
  559.   if (PromptStr)
  560.   {
  561.     strNcpy(N_ND->CurrentLine,PromptStr,MaxLen);
  562.  
  563.     if (PasswordChar) // Convert promptstr to a blanked out string..
  564.     {
  565.       for (editloop=0;N_ND->CurrentLine[editloop];editloop++)
  566.       {
  567.         if (Flags & GL_SYSOP)
  568.         {
  569.           PutConChar(PasswordChar);
  570.         }
  571.         else
  572.         {
  573.           PutChar(PasswordChar);
  574.         }
  575.       }
  576.     }
  577.     else
  578.     {
  579.       if (Flags & GL_SYSOP)
  580.       {
  581.         PutConText(N_ND->CurrentLine);
  582.       }
  583.       else
  584.       {
  585.         PutText(N_ND->CurrentLine);
  586.       }
  587.     }
  588.     xpos=strlen(N_ND->CurrentLine);
  589.   }
  590.  
  591.   if ((N_ND->LoginType==LOGIN_REMOTE) && (CarrierLost())) retval=IN_LOSSCARRIER;
  592.  
  593.   while (retval==IN_NOTHING)
  594.   {
  595.     // we only want to read the serial port if a) it's open and b) if we're
  596.     // still awaiting connect or someone is logged on..
  597.  
  598.     if (N_ND->SerOK && N_ND->LoginType !=LOGIN_LOCAL && (!(Flags & GL_SYSOP))  && (!(N_ND->NodeFlags & NFLG_BLOCKSERIAL)))
  599.     {
  600.       if (!N_ND->SerWaiting) SendSerReadData();
  601.     }
  602.  
  603.     // we ALWAYS want to read the console if the console window is open.
  604.     // cos the sysop might wanna do sommat!
  605.  
  606.     if (!N_ND->ConWaiting && N_ND->ConOK) ConReadData(1);
  607.  
  608.     // Submit Timer for Inactivity Disconnect..
  609.  
  610.  
  611.     if (!N_ND->NodeSettings.InactivityDisconnectOverride)
  612.     {
  613.       if (!(Flags & GL_NOINACTIVITY))
  614.       {
  615.         if (N_ND->User.Valid && !N_ND->RunningAwait)
  616.         {
  617.             TO_TD=SubmitTimer(N_ND->NodeTimer,N_ND->NodeSettings.InactivitySeconds,0);
  618.         }
  619.       }
  620.     }
  621.  
  622.     // Submit Timer for time allowed to enter string without chars being pressed.
  623.  
  624.     if (Timeout)
  625.     {
  626.       TD=SubmitTimer(N_ND->NodeTimer,Timeout,0);
  627.     }
  628.  
  629.     // Submit Timer for time allowed to enter string without chars being pressed.
  630.  
  631.     if (N_ND->User.Valid && !N_ND->RunningAwait)
  632.     {
  633.       if (N_ND->User.Acs.Data[ACS_UNLIMTIME]=='N' && HBBS_TimeLeft()+1>0)
  634.       {
  635.         TL_TD=SubmitTimer(N_ND->NodeTimer,HBBS_TimeLeft()+1 * 60,0);
  636.       }
  637.     }
  638.  
  639.  
  640.     SetUpSigs();
  641.  
  642.     ClrSignal(N_ND->TimerSig);  // if we don't do this we keep getting signals when nothing has happened.
  643.                                 // note: it took me ages to find this.... Argh!  The symptom was that all the
  644.                                 // cpu time disappeared when the bbs was waiting for input :-)! The complete
  645.                                 // opposite of normal operation
  646.  
  647.     ReturnedSigs=WaitAllSigs();
  648.     HandleMiscSigs(ReturnedSigs);
  649.  
  650.     // check olm's ?  *C* add an option/flag to NOT check for OLM's..
  651.  
  652.     if ((!(N_ND->NodeFlags & NFLG_HANDLINGOLM)) && (!(Flags & GL_NOOLM)) && (ReturnedSigs & (1L << N_ND->OLMPort->mp_SigBit)) && (N_ND->NodeFlags & NFLG_OLMSWAITING))
  653.     {
  654.       GoSystemDoor("ReadOLM",NULL);
  655.  
  656.       xpos=0;
  657.       ReDrawLine(Flags,&xpos);
  658.     }
  659.  
  660.     if (TO_TD)
  661.     {
  662.       if (CheckTimer(N_ND->NodeTimer,TO_TD))
  663.       {
  664.         TO_TD=NULL;
  665.         PutText("\r\n\r\nInactivityTimeout!\r\n\r\n"); //*C* make configurable, add option for executing door.
  666.  
  667.         GoSystemDoor("InactivityTimeout",NULL);
  668.  
  669.         sprintf(tmpstr,"Inactivity Timeout after %d seconds",N_ND->NodeSettings.InactivitySeconds);
  670.         HBBS_AddToCallersLog(tmpstr);
  671.  
  672.         N_ND->Actions[ACTN_INACTIVITYTIMEOUT]=ACTC_INACTIVITYTIMEOUT;
  673.  
  674.         // do stuff needed for sucessful hanging up of phone (actually this just sets the
  675.         // os_onlinestatus, the door must check this...
  676.  
  677.         DOOR_Goodbye();
  678.         DOOR_HangUp(); // *C* check this is needed
  679.         retval=IN_LOSSCARRIER;
  680.       }
  681.       else
  682.       {
  683.  
  684.         // If we have an inactivity timer then we need to restart the timer
  685.         // as a key has been pressed
  686.  
  687.         AbortTimer(N_ND->NodeTimer,TO_TD);
  688.         TO_TD=NULL;
  689.       }
  690.     }
  691.  
  692.     if (TL_TD)
  693.     {
  694.       if (CheckTimer(N_ND->NodeTimer,TL_TD))
  695.       {
  696.         TL_TD=NULL;
  697.         retval=IN_TIMEOUT;
  698.       }
  699.       else
  700.       {
  701.         AbortTimer(N_ND->NodeTimer,TL_TD);
  702.         TL_TD=NULL;
  703.       }
  704.  
  705.     }
  706.  
  707.     if (Timeout && retval==IN_NOTHING)
  708.     {
  709.       if (TD)
  710.       {
  711.         if (CheckTimer(N_ND->NodeTimer,TD))
  712.         {
  713.           TD=NULL;
  714.           retval=IN_TIMEOUT;
  715.  
  716.           if ((Flags & GL_DISPLAY) && !(Flags & GL_NORETURN))
  717.           {
  718.             if (Flags & GL_SYSOP)
  719.             {
  720.               PutConText("\r\n");
  721.             }
  722.             else
  723.             {
  724.               PutText("\r\n");
  725.             }
  726.           }
  727.         }
  728.         else
  729.         {
  730.           // a key has been pressed so restart timer for string entry.
  731.           AbortTimer(N_ND->NodeTimer,TD);
  732.           TD=NULL;
  733.         }
  734.       }
  735.     }
  736.  
  737.     if (N_ND->RequestShutdown) retval=IN_SHUTDOWN;
  738.     if (N_ND->LoginType==LOGIN_REMOTE && CarrierLost()) retval=IN_LOSSCARRIER;
  739.  
  740.     while (retval==IN_NOTHING && HandleConSerSigs(ReturnedSigs)) // swapped!
  741.     {
  742.       // key press, restart timer!
  743.       if (Timeout)
  744.       {
  745.         if (TD) AbortTimer(N_ND->NodeTimer,TD);
  746.         TD=SubmitTimer(N_ND->NodeTimer,Timeout,0);
  747.       }
  748.       // ok, we got some data from somehwere...
  749.  
  750.       CurrentChar[0]=N_ND->IBuffer[0];
  751.  
  752.       // checkcsi() needs to know EXACTLY where to look for incoming data
  753.  
  754.       csitype=CheckCSI(CurrentChar[0],ReturnedSigs & N_ND->ConSig ? GET_CONSOLE : GET_SERIAL);
  755.       switch (csitype)
  756.       {
  757.         case KEY_CSI:
  758.           {
  759.             if (Flags & GL_EDIT)
  760.             {
  761.               if (strcmp(N_ND->csistring,str_CSI_CURSORLEFT)==0)
  762.               {
  763.                 if (xpos>0)
  764.                 {
  765.                   xpos--;
  766.                   if (Flags & GL_DISPLAY)
  767.                   {
  768.                     if (Flags & GL_SYSOP)
  769.                     {
  770.                       PutConText("\033[1D");
  771.                     }
  772.                     else
  773.                     {
  774.                       PutText("\033[1D");
  775. //                      CursorLeft(1);
  776.                     }
  777.                   }
  778.                 }
  779.               }
  780.               else
  781.               {
  782.                 if (strcmp(N_ND->csistring,str_CSI_CURSORRIGHT)==0)
  783.                 {
  784.                   if (xpos<strlen(N_ND->CurrentLine))
  785.                   {
  786.                     xpos++;
  787.                     if (Flags & GL_DISPLAY)
  788.                     {
  789.                       if (Flags & GL_SYSOP)
  790.                       {
  791.                         PutConText("\033[1C");
  792.                       }
  793.                       else
  794.                       {
  795.                         PutText("\033[1C");
  796.   //                      CursorRight(1);
  797.                       }
  798.                     }
  799.                   }
  800.                 }
  801.                 else
  802.                 {
  803.                   if ((Flags & GL_HISTORY) && (HistoryItems>0))
  804.                   {
  805.                     if (strcmp(N_ND->csistring,str_CSI_CURSORUP)==0)
  806.                     {
  807.                       if (HistoryNum>0)
  808.                       {
  809.                         HistoryNum--;
  810.                       }
  811.                     }
  812.  
  813.                     if (strcmp(N_ND->csistring,str_CSI_CURSORDOWN)==0)
  814.                     {
  815.                       if (HistoryNum<HistoryItems)
  816.                       {
  817.                         HistoryNum++;
  818.                       }
  819.                     }
  820.  
  821.                     if (HistoryNum!=OldHistNum)
  822.                     {
  823.                       if (HistoryNum<HistoryItems)
  824.                       {
  825.                         strNcpy(N_ND->CurrentLine,HBBS_ListName(HistoryList,HistoryNum),MaxLen);
  826.                         OldHistNum=HistoryNum;
  827.                       }
  828.                       else
  829.                       {
  830.                         N_ND->CurrentLine[0]=0; // erase the line.. :-)
  831.                         HistoryNum=HistoryItems;
  832.                         OldHistNum=-1;
  833.                       }
  834.                       ReDrawLine(Flags,&xpos);
  835.                     }
  836.                   }
  837.                 }
  838.               }
  839.             }
  840.             retval=CheckFunctionKeys();
  841.           }
  842.           break;
  843.         case KEY_ESCAPE:
  844.           handleescape();
  845.           // CheckCSI will leave one the character following the escape key
  846.           // in the buffer. so reset out mini string again..
  847.           CurrentChar[0]=N_ND->IBuffer[0];
  848.           // no break so we process the next char as well..
  849.         case KEY_NONE:
  850.           if (N_ND->LoginType!=LOGIN_NONE || ReturnedSigs & N_ND->SerSig)
  851.           {
  852.             if (CurrentChar[0]>=0x20) // i.e. not unprintable or a control char..
  853.             {
  854.               if (CurrentChar[0]==127) // DEL
  855.               {
  856.                 if (Flags & GL_EDIT)
  857.                 {
  858.                   editlen=strlen(N_ND->CurrentLine);
  859.                   if (xpos!=editlen)
  860.                   {
  861.                     for (editloop=xpos;editloop<((editlen<MaxLen ? editlen:MaxLen));editloop++) // <= to copy the null terminator as well!
  862.                     {
  863.                       N_ND->CurrentLine[editloop]=N_ND->CurrentLine[editloop+1];
  864.                     }
  865.                     if (Flags & GL_DISPLAY)
  866.                     {
  867.                       if (Flags & GL_SYSOP)
  868.                       {
  869.                         PutConText("\033[1P");
  870.                       }
  871.                       else
  872.                       {
  873.                         PutText("\033[1P");
  874.                         if (Flags & GL_NODISTURB)
  875.                         {
  876.                           if (xpos==MaxLen-1)
  877.                           {
  878.                             strcpy(cmovestr,"\033[@");
  879.                           }
  880.                           else
  881.                           {
  882.                             sprintf(cmovestr,"\033[%dC\033[@\033[%dD",MaxLen-xpos-1,MaxLen-xpos-1);
  883.                           }
  884.                           PutText(cmovestr);
  885.                         }
  886.                       }
  887.                     }
  888.                   }
  889.                 }
  890.               }
  891.               else
  892.               {
  893.                 if (Flags & GL_CVTUPPER) CurrentChar[0]=toupper(CurrentChar[0]);
  894.  
  895.                 AddOK=FALSE;
  896.                 if (Flags & GL_USECHARS)
  897.                 {
  898.                   if (strchr(N_ND->CharsAllowed,CurrentChar[0]))
  899.                   {
  900.                     AddOK=TRUE;
  901.                   }
  902.                   else
  903.                   {
  904.                     // ooh, wrong char, lets do a beep..
  905.                     if (!(Flags & GL_NOBEEP))
  906.                     {
  907.                       // but only if we're allowed to!
  908.                       if (Flags & GL_SYSOP)
  909.                       {
  910.                         PutConChar(7); // 7 = BEEP char!
  911.                       }
  912.                       else
  913.                       {
  914.                         PutChar(7);
  915.                       }
  916.                     }
  917.                   }
  918.                 } else AddOK=TRUE;
  919.                 if (AddOK)
  920.                 {
  921.                   // ok, no function key pressed, so add the char to the end of the string...
  922.                   if ((editlen=strlen(N_ND->CurrentLine)) < (LEN_CURRENTLINE < MaxLen ? LEN_CURRENTLINE : MaxLen))
  923.                   {
  924.                     if (xpos==editlen) // tag char on end ?
  925.                     {
  926.                       xpos++;
  927.                       strcat(N_ND->CurrentLine,CurrentChar);
  928.                       if (Flags & GL_DISPLAY)
  929.                       {
  930.                         if (Flags & GL_SYSOP)
  931.                         {
  932.                           if (PasswordChar) PutConChar(PasswordChar); else PutConChar(CurrentChar[0]);
  933.                         }
  934.                         else
  935.                         {
  936.                           if (PasswordChar) PutChar(PasswordChar); else PutChar(CurrentChar[0]);
  937.                         }
  938.                       }
  939.                     }
  940.                     else
  941.                     {
  942.                       if (Flags & GL_EDIT)
  943.                       {
  944.                         // gotta insert char!
  945.                         for (editloop=editlen+1; editloop>xpos ;editloop--) //+1 for null terminator
  946.                         {
  947.                           N_ND->CurrentLine[editloop]=N_ND->CurrentLine[editloop-1];
  948.                         }
  949.                         N_ND->CurrentLine[xpos]=CurrentChar[0];
  950.                         if (Flags & GL_DISPLAY)
  951.                         {
  952.                           if (Flags & GL_SYSOP)
  953.                           {
  954.                             PutConText("\033[1@");
  955.                             PutConChar(CurrentChar[0]);
  956.                           }
  957.                           else
  958.                           {
  959.                             PutText("\033[1@");
  960.                             PutChar(CurrentChar[0]);
  961.                             if (Flags & GL_NODISTURB)
  962.                             {
  963.                               sprintf(cmovestr,"\033[%dC\033[P\033[%dD",MaxLen-xpos-1,MaxLen-xpos-1);
  964.                               PutText(cmovestr);
  965.                             }
  966.                           }
  967.                         }
  968.                         xpos++;
  969.                       }
  970.                     }
  971.                   }
  972.                 }
  973.               }
  974.             }
  975.             else
  976.             {
  977.               switch (CurrentChar[0])
  978.               {
  979.                 case 13: // return
  980.                   if ((Flags & GL_DISPLAY) && !(Flags & GL_NORETURN)) PutText(str_CRLF); // linefeed...
  981.                   retval=IN_GOTLINE;
  982.                   break;
  983.  
  984.                 case 27: //escape
  985.                   handleescape();
  986.                   break;
  987.  
  988.                 case 3: //ctrl+c
  989.                   if (!(N_ND->NodeFlags & NFLG_CTRLC)) N_ND->NodeFlags+=NFLG_CTRLC;
  990.                   break;
  991.                 case 24: //ctrl+x, clear the line..
  992.                   N_ND->CurrentLine[0]=0;
  993.                   ReDrawLine(Flags,&xpos);
  994.                   break;
  995.  
  996.                 case 8: //backspace
  997.                   if (Flags & GL_EDIT)
  998.                   {
  999.                     if (xpos>0)
  1000.                     {
  1001.                       xpos--;
  1002.                       editlen=strlen(N_ND->CurrentLine);
  1003.                       for (editloop=xpos;editloop<editlen;editloop++) // <= to copy the null terminator as well!
  1004.                       {
  1005.                         N_ND->CurrentLine[editloop]=N_ND->CurrentLine[editloop+1];
  1006.                       }
  1007.                       if (Flags & GL_DISPLAY)
  1008.                       {
  1009.                         if (Flags & GL_SYSOP)
  1010.                         {
  1011.                           PutConText("\033[1D\033[1P");
  1012.                         }
  1013.                         else
  1014.                         {
  1015.                           if (Flags & GL_NODISTURB)
  1016.                           {
  1017.                             if (xpos==MaxLen-1)
  1018.                             {
  1019.                               strcpy(cmovestr,"\033[@");
  1020.                             }
  1021.                             else
  1022.                             {
  1023.                               sprintf(cmovestr,"\033[%dC\033[@\033[%dD",MaxLen-xpos-1,MaxLen-xpos-1);
  1024.                             }
  1025.                             PutText(cmovestr);
  1026.                           }
  1027.                           PutText("\033[1D\033[1P");
  1028. //                          CursorLeft(1);
  1029. //                          DeleteChars(1);
  1030.                         }
  1031.                       }
  1032.                     }
  1033.                   }
  1034.                   break;
  1035.               }
  1036.             }
  1037.           }
  1038.           break;
  1039.       }
  1040.     }
  1041.     if (retval==IN_NOTHING)
  1042.     {
  1043.       if ((strlen(N_ND->CurrentLine)==MaxLen) && (Flags & GL_IMMEDIATE))
  1044.       {
  1045.         retval=IN_GOTLINE;
  1046.  
  1047.         if (Flags & GL_LINEWRAP)
  1048.         {
  1049.           if (strptr=strrchr(N_ND->CurrentLine,' '))
  1050.           {
  1051.             if (Flags & GL_DISPLAY)
  1052.             {
  1053.               sprintf(cmovestr,"\033[%dD\033[K",strlen(N_ND->CurrentLine)-(strptr-N_ND->CurrentLine));
  1054.               if (Flags & GL_SYSOP)
  1055.               {
  1056.                 PutConText(cmovestr);
  1057.               }
  1058.               else
  1059.               {
  1060.                 PutText(cmovestr);
  1061.               }
  1062.             }
  1063.  
  1064.             strcpy(N_ND->CurrentLineWrap,strptr+1);
  1065.             *strptr=0;
  1066.  
  1067.             // *C* update the display!
  1068.           }
  1069.         }
  1070.  
  1071.  
  1072.         if ((Flags & GL_DISPLAY) && !(Flags & GL_NORETURN)) PutText(str_CRLF); // linefeed...
  1073.       }
  1074.     }
  1075.   }
  1076.  
  1077.   AbortTimer(N_ND->NodeTimer,TD);
  1078.   AbortTimer(N_ND->NodeTimer,TO_TD);
  1079.   AbortTimer(N_ND->NodeTimer,TL_TD);
  1080.  
  1081.   if (Flags & GL_HISTORY)
  1082.   {
  1083.     if (N_ND->CurrentLine[0])
  1084.     {
  1085.       if (!NewStrNode(N_ND->CurrentLine,HistoryList))
  1086.       {
  1087.         HistoryItems++;
  1088.       }
  1089.     }
  1090.   }
  1091.  
  1092.   if (retval==IN_LOSSCARRIER)
  1093.   {
  1094.     N_ND->OnlineStatus=OS_OFFLINE;
  1095.     if (Flags & GL_DISPLAY) PutConText(str_CRLF);
  1096.   }
  1097.   return(retval);
  1098. }
  1099.  
  1100. void RunDoor(char *doorname,char *options,BOOL DebugMode,BOOL ASync)
  1101. {
  1102.   // function to start a door
  1103.   // *C* have timeout on door, check file exists before attempting to run it...
  1104.  
  1105.   char cmd[BIG_STR],outstr[BIG_STR+300];
  1106. //  sprintf(cmd,"%s %d %s",doorname,N_NodeNum,options ? options : "\0");
  1107.   sprintf(outstr,"%d",N_NodeNum);
  1108.   replace(cmd,doorname,"{O}",options ? options : ""); //replace won't work with a null string
  1109.   replace(cmd,cmd,"{N}",outstr);
  1110.  
  1111.   // if doorlog is on then write to the doorlog file!
  1112.   if (N_ND->NodeSettings.DoorLog || N_ND->DoorLogOverride)
  1113.   {
  1114.     HBBS_GetDate(outstr);
  1115.     strcat(outstr," ");
  1116.     HBBS_GetTime(outstr+strlen(outstr));
  1117.     sprintf(outstr+strlen(outstr)," Handle: %s, Conf: %s, Door: %s\n",N_ND->User.CallData.Handle,N_ND->CurrentConf ? N_ND->CurrentConf->node.ln_Name : "None Joined",cmd);
  1118.     HBBS_AppendStrToFile(N_ND->NodeSettings.DoorLogFile,outstr);
  1119.   }
  1120.  
  1121.   if (DebugMode)
  1122.   {
  1123.  
  1124.     printf("DOOR DEBUG MODE ON - Start the door with the settings below!\n"
  1125.            "==============================================================================\n"
  1126.            "%s\n"
  1127.            "==============================================================================\n",cmd);
  1128.   }
  1129.   else
  1130.   {
  1131.     HBBS_RunDOSCMD(cmd,ASync);
  1132.   }
  1133. }
  1134.  
  1135. struct MsgPort* CreateDoorStartPort( void )
  1136. {
  1137.   struct MsgPort *DP=NULL;
  1138.   sprintf(N_ND->DoorStartPortName,"DoorStart_N%d_D%d",N_ND->NodeNum,N_ND->DoorsRunning+1);
  1139.   DP=CreatePort(N_ND->DoorStartPortName,0);
  1140.   return(DP);
  1141. }
  1142.  
  1143. BOOL CheckDoorStarted(struct MsgPort *DP,char *systemoptions)
  1144. {
  1145.   struct DoorActivityMsg *DM;
  1146.   BOOL retval=FALSE;
  1147.  
  1148.   while (DM=(struct DoorActivityMsg *)GetMsg(DP))
  1149.   {
  1150.     N_ND->ActiveDoor->SystemOptions=systemoptions;
  1151.     ReplyMsg((struct Message *)DM);
  1152.     retval=TRUE;
  1153.   }
  1154.   return(retval);
  1155. }
  1156.  
  1157. void GoDoor(char *doorname,char *systemoptions,char *options,BOOL DebugMode)
  1158. {
  1159.   ULONG ReturnedSigs;
  1160.   struct DoorData *CurrentDoor;
  1161.   struct TimerData *TD;
  1162.   BOOL timeout,doorstarted;
  1163.   struct MsgPort *DP;
  1164.   char *clinesave=N_ND->CurrentLine; // save old line..
  1165.  
  1166. // *C* Why have I commented this out ?  is it because of the {N} {O}'s etc... i think it might be!
  1167. //  if (PathOK(doorname)) // does door exist ?
  1168. //  {
  1169. //    strcpy(N_ND->Action,"Loading Door!");
  1170. //    DOOR_UpdateNodeStatus(UPD_ACTION);
  1171.  
  1172.     if (N_ND->CurrentLine=AllocVec(LEN_CURRENTLINE,MEMF_PUBLIC))
  1173.     {
  1174.       N_ND->CurrentLine[0]=0;
  1175.  
  1176.       if (TD=SubmitTimer(N_ND->NodeTimer,BBSGlobal->Door_Timeout,0))
  1177.       {
  1178.         timeout=FALSE;
  1179.         doorstarted=FALSE;
  1180.  
  1181.         if (DP=CreateDoorStartPort())
  1182.         {
  1183.           N_ND->ActiveDoor=NULL;
  1184.           RunDoor(doorname,options,DebugMode,TRUE);
  1185.  
  1186. //        strcpy(N_ND->Action,"Waiting For Door");
  1187. //        DOOR_UpdateNodeStatus(UPD_ACTION);
  1188.  
  1189.           do
  1190.           {
  1191.             Wait (1L<<DP->mp_SigBit | DEF_PORTSIG | DEF_TIMERSIG);
  1192.             doorstarted=CheckDoorStarted(DP,systemoptions);
  1193.             if (timeout=CheckTimer(N_ND->NodeTimer,TD))
  1194.             {
  1195.               TD=NULL;
  1196.             }
  1197.           } while(doorstarted==FALSE && timeout==FALSE);
  1198.  
  1199.           DeletePort(DP);
  1200.  
  1201.           if (timeout)
  1202.           {
  1203.             HBBS_LogError(N_ND->NodeSettings.NodeLogFile,ERR_DOORTIMEOUT,doorname,TYPE_WARNING);
  1204.           }
  1205.           else
  1206.           {
  1207.             if (TD) AbortTimer(N_ND->NodeTimer,TD);
  1208.  
  1209.             strNcpy(N_ND->Action,N_ND->ActiveDoor->node.ln_Name,MAX_ACTION_LEN);
  1210.             DOOR_UpdateNodeStatus(UPD_ACTION);
  1211.  
  1212.             if (N_ND->ActiveDoor!=NULL)
  1213.             {
  1214.               // This next loop is essentially the main loop of the bbs when
  1215.               // a door is running! :-)
  1216.  
  1217.               // wait until the door stops!
  1218.  
  1219.               CurrentDoor=N_ND->ActiveDoor;
  1220.               do
  1221.               {
  1222.                 SetUpDoorSigs();
  1223.                 ReturnedSigs=Wait(N_ND->ConWinSig |
  1224.                                   N_ND->SettingsWinSig |
  1225.                                   N_ND->InfoWinSig |
  1226.                                   N_ND->WinSig |
  1227.                                   N_ND->PortSig);
  1228.  
  1229.                 HandleMiscSigs(ReturnedSigs);
  1230.  
  1231.                 // while the door is started we should check for function key presses
  1232.                 // and so on... (which is handled by HandleDoorMsg())
  1233.  
  1234.  
  1235.                 // repeat wait loop until the door is finished, can detect by looking to see
  1236.                 // what the value of the door pointer is when it starts, and then keep comparing
  1237.                 // that to the the ActiveDoor pointer, if they differ the door has closed (as
  1238.                 // the ActiveDoor Pointer would point to a different door or to NULL...
  1239.               } while (N_ND->ActiveDoor==CurrentDoor);
  1240.  
  1241.               if (DebugMode)
  1242.               {
  1243.                 printf("Door return: ");
  1244.                 puts(N_ND->DoorReturn);
  1245.               }
  1246.             }
  1247.           }
  1248.         }
  1249.         else
  1250.         {
  1251.           if (TD) AbortTimer(N_ND->NodeTimer,TD);
  1252.         }
  1253.       }
  1254.       FreeVec(N_ND->CurrentLine);
  1255.       N_ND->CurrentLine=clinesave;
  1256.     }
  1257. /* *C* Why have I commented this out ? .. because of the {x}'s you plonka!
  1258.   }
  1259.   else
  1260.   {
  1261.     sprintf(outstr,"The door file (%s) is missing!\r\n",doorname);
  1262.     PutText(outstr);
  1263.     HBBS_LogError(BBSGlobal->ErrorLogFile,ERR_GENERAL,outstr,TYPE_WARNING);
  1264.   }
  1265. */
  1266.   if (N_ND->ActiveDoor)
  1267.   {
  1268.     strNcpy(N_ND->Action,N_ND->ActiveDoor->node.ln_Name,MAX_ACTION_LEN);
  1269.     DOOR_UpdateNodeStatus(UPD_ACTION);
  1270.   }
  1271. }
  1272.  
  1273. void PrintList( struct List *list)
  1274. {
  1275.   struct Node *node;
  1276.   for (node = list->lh_Head ; node->ln_Succ ; node =node->ln_Succ)
  1277.   {
  1278.     puts(node->ln_Name);
  1279.   }
  1280. }
  1281.  
  1282. void CheckDoorTypes(char *actualtype,char *cmd,char *options)
  1283. {
  1284.   char tmpstr[BIG_STR],numstr[5];
  1285.  
  1286.   sprintf(numstr,"%d",N_NodeNum);
  1287.   replace(tmpstr,cmd,"{N}",numstr);
  1288.   replace(tmpstr,tmpstr,"{O}",options);
  1289.  
  1290.   if (stricmp(actualtype,"SCREEN")==0)
  1291.   {
  1292.     DisplayScreen(tmpstr);
  1293.   }
  1294.   else
  1295.   {
  1296.     if (stricmp(actualtype,"SSCREEN")==0)
  1297.     {
  1298.       DisplaySpecialScreen(tmpstr);
  1299.     }
  1300.     else
  1301.     {
  1302.       if (stricmp(actualtype,"CLS")==0)
  1303.       {
  1304.         PutText(ANSI_CLS);
  1305.       }
  1306.       else
  1307.       {
  1308.         if (stricmp(actualtype,"PAUSE")==0)
  1309.         {
  1310.           PausePrompt(tmpstr,0);
  1311.         }
  1312.         else
  1313.         {
  1314.           if (stricmp(actualtype,"ECHO")==0)
  1315.           {
  1316.             PutText(tmpstr);
  1317.             PutText("\r\n");
  1318.           }
  1319.           else
  1320.           {
  1321.             if (stricmp(actualtype,"DOS")==0)
  1322.             {
  1323.               HBBS_RunDOSCMD(tmpstr,FALSE);
  1324.             }
  1325.           }
  1326.         }
  1327.       }
  1328.     }
  1329.   }
  1330. }
  1331.  
  1332. #define GOSYS_CONF 1
  1333. #define GOSYS_NODE 2
  1334. #define GOSYS_CMDS 3
  1335.  
  1336. V_BOOL GoSystemDoor( char *doorname, char *options )
  1337. {
  1338.   /* must search the SYSTEM door list in the commands dir for first the conf,
  1339.   then the node and finally the hbbs:commands directories.. when it finds
  1340.   it it runs it, note that there may be more than one door to call at a time
  1341.   as you may define more than one door for each system function. e.g.
  1342.  
  1343.   Examine_Type_1=HBBS
  1344.   Examine_DOOR_1=HBBS:Doors/User/Examine/Examine.HBBS
  1345.   Examine_Param_1=
  1346.  
  1347.   Examine_Type_2=HBBS
  1348.   Examine_DOOR_2=HBBS:Doors/User/DIZTimeAdd/DIZTimeAdd.HBBS
  1349.   Examine_Param_2=[=- Uploaded At HH:MM -=]
  1350.  
  1351.   Examine_Type_3=HBBS
  1352.   Examine_DOOR_3=HBBS:Doors/User/Sentby/Sentby.HBBS
  1353.   Examine_Param_3=Sent,Cps,Node
  1354.  
  1355.   note: if you have say Examine_Type_1 in hbbs:conferences/newuser/commands/system
  1356.   and in hbbs:commands/system the set of commands in hbbs:commands/system WILL NOT
  1357.   be run as the former file has priority over the latter.
  1358.  
  1359.   */
  1360.  
  1361.   UBYTE filename[BIG_STR],*optionname,*actualparam=NULL,*actualtype=NULL;
  1362.   V_BOOL done=FALSE,DebugMode;
  1363.   short whichfile;
  1364.   struct CfgFileData *CfgFile;
  1365.   struct List *CmdList=NULL;
  1366.   struct Node *node;
  1367.   short doornum;
  1368.  
  1369.   N_ND->DoorReturn[0]=0; // null terminate string...
  1370.   N_ND->DoorContinue=TRUE;
  1371.  
  1372.   for (whichfile=GOSYS_CONF;whichfile<=GOSYS_CMDS && !done;whichfile++)
  1373.   {
  1374.  
  1375.  
  1376. //    if (stricmp("AWAIT",doorname)!=0 && stricmp("ACCOUNTEDIT",doorname)!=0 && N_ND->OnlineStatus==OS_OFFLINE)
  1377. //    {
  1378. //      done=TRUE;
  1379. //    }
  1380. //    else
  1381. //    {
  1382.     filename[0]=0;
  1383.     switch(whichfile)
  1384.     {
  1385.       case GOSYS_CONF:
  1386.         if (N_ND->CurrentConf) // have we joined a conf yet ?
  1387.         {
  1388.           strcpy(filename,N_ND->CurrentConf->ConfPath);
  1389.           strcat(filename,FILENAME_CMDSSYSTEM);
  1390.         }
  1391.         break;
  1392.       case GOSYS_NODE:
  1393.         strcpy(filename,N_ND->NodeLocation);
  1394.         strcat(filename,FILENAME_CMDSSYSTEM);
  1395.         break;
  1396.       case GOSYS_CMDS:
  1397.         strcpy(filename,FILE_HBBS);
  1398.         strcat(filename,FILENAME_CMDSSYSTEM);
  1399.         break;
  1400.     }
  1401.     if (filename[0]) // string present ?
  1402.     {
  1403.       if (optionname=AllocVec(strlen(doorname)+10,MEMF_PUBLIC))
  1404.       {
  1405.         strcpy(optionname,doorname);
  1406.         strcat(optionname,"_Door");
  1407.         if (CfgFile=HBBS_LoadConfig(filename,LCFG_NONE))
  1408.         {
  1409.           if (HBBS_GetSetting(CfgFile,(void *)&CmdList,VTYPE_STRINGLIST,optionname,OPT_MULTI))
  1410.           {
  1411.             for (doornum=1,node = CmdList->lh_Head ; N_ND->DoorContinue && node->ln_Succ ; node =node->ln_Succ,doornum++)
  1412.             {
  1413.               actualtype=NULL;
  1414.               sprintf(optionname,"%s_Type_%d",doorname,doornum);
  1415.               if (HBBS_GetSetting(CfgFile,(void *)&actualtype,VTYPE_STRING,optionname,OPT_SINGLE))
  1416.               {
  1417.                 actualparam=NULL;
  1418.                 sprintf(optionname,"%s_Param_%d",doorname,doornum);
  1419.                 HBBS_GetSetting(CfgFile,(void *)&actualparam,VTYPE_STRING,optionname,OPT_SINGLE);
  1420.                 if (!actualparam) actualparam=DupStr("");
  1421.                 if (actualparam)
  1422.                 {
  1423.                   done=TRUE;
  1424.  
  1425.                   DebugMode=FALSE;
  1426.  
  1427.                   sprintf(optionname,"%s_Debug_%d",doorname,doornum);
  1428.                   HBBS_GetSetting(CfgFile,(void *)&DebugMode,VTYPE_BOOL,optionname,OPT_SINGLE);
  1429.  
  1430.                   if (stricmp(actualtype,"HBBS")==0) //changed from "NORMAL" on 1-JULY-96
  1431.                   {
  1432.                     GoDoor(node->ln_Name,actualparam,options,DebugMode);
  1433.                   }
  1434.                   else
  1435.                   {
  1436.                     if (stricmp(actualtype,"CLI")==0)
  1437.                     {
  1438.                       RunDoor(node->ln_Name,options,DebugMode,FALSE);
  1439.                     }
  1440.                     else
  1441.                     {
  1442.                       CheckDoorTypes(actualtype,node->ln_Name,options);
  1443.                     }
  1444.                   }
  1445.                   FreeStr(actualparam);
  1446.                 }
  1447.                 FreeStr(actualtype);
  1448.               }
  1449.             }
  1450.             FreeStrList(CmdList);
  1451.           }
  1452.           HBBS_FlushConfig(CfgFile);
  1453.         }
  1454.         FreeVec(optionname);
  1455.       }
  1456.     }
  1457. //    }
  1458.   }
  1459.   return(done);
  1460. }
  1461.  
  1462. short WhatAccessNode(V_SMALLNUM accesslevel)
  1463. {
  1464.   // returns the struct node number of the specified access level
  1465.   // mainly used when you want to find the name of an access level
  1466.  
  1467.   short retval=-1;
  1468.   char tmpstr[10];
  1469.   short loop;
  1470.   struct Node *node;
  1471.  
  1472.  
  1473.   sprintf(tmpstr,"%d",accesslevel);
  1474.  
  1475.   for (loop=0,node = BBSGlobal->AcsLevelList->lh_Head ; node->ln_Succ && retval==-1 ; node =node->ln_Succ,loop++)
  1476.   {
  1477.     if (strcmp(tmpstr,node->ln_Name)==0)
  1478.     {
  1479.       retval=loop;
  1480.     }
  1481.   }
  1482.   return(retval);
  1483. }
  1484.  
  1485. #define GOUSER_CONF 1
  1486. #define GOUSER_NODE 2
  1487. #define GOUSER_CMDS 3
  1488.  
  1489.  
  1490. V_BOOL GoUserDoor( char *doorname, char *options )
  1491. {
  1492.  
  1493.   /* this door must first determine the current access level, then scan the following
  1494.      files to find out what door to run.
  1495.  
  1496.      CurrentConf/Commands/Level_XX
  1497.      CurrentConf/Commands/AllLevels
  1498.      Currentnode/Commands/Level_XX
  1499.      Currentnode/Commands/AllLevels
  1500.      HBBS:Commnds/Level_XX
  1501.      HBBS:Commnds/AllLevels
  1502.  
  1503.      then when it finds the door to run it calls it up!
  1504.  
  1505.   */
  1506.  
  1507.   UBYTE dirname[BIG_STR],filename[BIG_STR],*optionname,*actualparam=NULL,*actualtype=NULL;
  1508.   V_BOOL done=FALSE,DebugMode,SearchedAll;
  1509.   short whichfile;
  1510.   struct CfgFileData *CfgFile;
  1511.   struct List *CmdList=NULL;
  1512.   struct Node *node;
  1513.   short doornum,CurrentAccess;
  1514.  
  1515.   N_ND->DoorReturn[0]=0; // null terminate string...
  1516.   N_ND->DoorContinue=TRUE;
  1517.  
  1518.   for (whichfile=GOUSER_CONF;whichfile<=GOUSER_CMDS && !done;whichfile++)
  1519.   {
  1520.     dirname[0]=0;
  1521.     filename[0]=0;
  1522.     switch(whichfile)
  1523.     {
  1524.       case GOUSER_CONF:
  1525.         if (N_ND->CurrentConf) // have we joined a conf yet ?
  1526.         {
  1527.           sprintf(dirname,"%sCommands/",N_ND->CurrentConf->ConfPath);
  1528.         }
  1529.         break;
  1530.       case GOUSER_NODE:
  1531.         sprintf(dirname,"%sCommands/",N_ND->NodeLocation);
  1532.         break;
  1533.       case GOUSER_CMDS:
  1534.         strcpy(dirname,"HBBS:Commands/");
  1535.         break;
  1536.     }
  1537.     if (dirname[0]) // string present ? cos it might not be if we ain't in a conf..
  1538.     {
  1539.       // ok, no we know where to look for the commands, so we gotta check
  1540.       // "Level_<access>" downto "Level_00" until we find it, if it ain't there then
  1541.       // we have to check "All_Levels"
  1542.  
  1543.       SearchedAll=FALSE;
  1544.       CurrentAccess=WhatAccessNode(N_ND->User.CallData.Access);
  1545.  
  1546.       do
  1547.       {
  1548.         if (CurrentAccess<0)
  1549.         {
  1550.           sprintf(filename,"%sAll_Levels",dirname);
  1551.           SearchedAll=TRUE;
  1552.         }
  1553.         else
  1554.         {
  1555.           node=GetNode(BBSGlobal->AcsLevelList,CurrentAccess);
  1556.  
  1557.           sprintf(filename,"%sLevel_%s",dirname,node->ln_Name);
  1558.         }
  1559.  
  1560.         if (optionname=AllocVec(strlen(doorname)+10,MEMF_PUBLIC))
  1561.         {
  1562.           sprintf(optionname,"%s_Door",doorname);
  1563.           if (CfgFile=HBBS_LoadConfig(filename,LCFG_NONE))
  1564.           {
  1565.             if (HBBS_GetSetting(CfgFile,(void *)&CmdList,VTYPE_STRINGLIST,optionname,OPT_MULTI))
  1566.             {
  1567.               for (doornum=1,node = CmdList->lh_Head ; N_ND->DoorContinue && node->ln_Succ ; node =node->ln_Succ,doornum++)
  1568.               {
  1569.                 actualtype=NULL;
  1570.                 sprintf(optionname,"%s_Type_%d",doorname,doornum);
  1571.                 if (HBBS_GetSetting(CfgFile,(void *)&actualtype,VTYPE_STRING,optionname,OPT_SINGLE))
  1572.                 {
  1573.                   actualparam=NULL;
  1574.                   sprintf(optionname,"%s_Param_%d",doorname,doornum);
  1575.                   HBBS_GetSetting(CfgFile,(void *)&actualparam,VTYPE_STRING,optionname,OPT_SINGLE);
  1576.                   if (!actualparam) actualparam=DupStr("");
  1577.                   if (actualparam)
  1578.                   {
  1579.                     DebugMode=FALSE;
  1580.                     if (stricmp(actualtype,"HBBS")==0)
  1581.                     {
  1582.                       sprintf(optionname,"%s_Debug_%d",doorname,doornum);
  1583.                       HBBS_GetSetting(CfgFile,(void *)&DebugMode,VTYPE_BOOL,optionname,OPT_SINGLE);
  1584.  
  1585.                       GoDoor(node->ln_Name,actualparam,options,DebugMode);
  1586.                     }
  1587.                     else
  1588.                     {
  1589.                       if (stricmp(actualtype,"CLI")==0)
  1590.                       {
  1591.                         RunDoor(node->ln_Name,options,DebugMode,FALSE);
  1592.                       }
  1593.                       else
  1594.                       {
  1595.                         CheckDoorTypes(actualtype,node->ln_Name,options);
  1596.                       }
  1597.                     }
  1598.                     FreeStr(actualparam);
  1599.                   }
  1600.                   FreeStr(actualtype);
  1601.                 }
  1602.               }
  1603.               FreeStrList(CmdList);
  1604.               done=TRUE;
  1605.             }
  1606.             HBBS_FlushConfig(CfgFile);
  1607.           }
  1608.           FreeVec(optionname);
  1609.         }
  1610.         CurrentAccess--;
  1611.  
  1612.       } while (!( done || SearchedAll));
  1613.  
  1614.     }
  1615.   }
  1616.   return(done);
  1617. }
  1618.  
  1619. // *M* Move routines into HBBSNode.C
  1620.  
  1621. void Add_Last_Caller(char *data)
  1622. {
  1623.   struct Node *node;
  1624.  
  1625.   if (N_ND->Current_Last_Callers==N_ND->Max_Last_Callers)  // *C* make configurable
  1626.   {
  1627.     node=RemTail(N_ND->Last_Callers);
  1628.     FreeStr(node->ln_Name);
  1629.     FreeVec(node);
  1630.     N_ND->Current_Last_Callers--;
  1631.   }
  1632.   if (node=(struct Node*)AllocVec(sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR))
  1633.   {
  1634.     node->ln_Name=DupStr(data);
  1635.     AddHead(N_ND->Last_Callers,node);
  1636.     N_ND->Current_Last_Callers++;
  1637.   }
  1638.   UpdateInfoWin();
  1639.   SendRequest(REQ_UPDATEINFO);
  1640. }
  1641.  
  1642. void Add_Last_PWFail(char *data)
  1643. {
  1644.   struct Node *node;
  1645.  
  1646.   if (N_ND->Current_Last_PWFails==N_ND->Max_Last_PWFails)
  1647.   {
  1648.     node=RemTail(N_ND->Last_PWFails);
  1649.     FreeStr(node->ln_Name);
  1650.     FreeVec(node);
  1651.     N_ND->Current_Last_PWFails--;
  1652.   }
  1653.   if (node=(struct Node*)AllocVec(sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR))
  1654.   {
  1655.     node->ln_Name=DupStr(data);
  1656.     AddHead(N_ND->Last_PWFails,node);
  1657.     N_ND->Current_Last_PWFails++;
  1658.   }
  1659.   UpdateInfoWin();
  1660.   SendRequest(REQ_UPDATEINFO);
  1661. }
  1662.  
  1663. void Add_Last_Download(char *data)
  1664. {
  1665.   struct Node *node;
  1666.  
  1667.   if (N_ND->Current_Last_Downloads==N_ND->Max_Last_Downloads)
  1668.   {
  1669.     node=RemTail(N_ND->Last_Downloads);
  1670.     FreeStr(node->ln_Name);
  1671.     FreeVec(node);
  1672.     N_ND->Current_Last_Downloads--;
  1673.   }
  1674.   if (node=(struct Node*)AllocVec(sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR))
  1675.   {
  1676.     node->ln_Name=DupStr(data);
  1677.     AddHead(N_ND->Last_Downloads,node);
  1678.     N_ND->Current_Last_Downloads++;
  1679.   }
  1680.   UpdateInfoWin();
  1681.   SendRequest(REQ_UPDATEINFO);
  1682. }
  1683.  
  1684. void Add_Last_Upload(char *data)
  1685. {
  1686.   struct Node *node;
  1687.  
  1688.   if (N_ND->Current_Last_Uploads==N_ND->Max_Last_Uploads)
  1689.   {
  1690.     node=RemTail(N_ND->Last_Uploads);
  1691.     FreeStr(node->ln_Name);
  1692.     FreeVec(node);
  1693.     N_ND->Current_Last_Uploads--;
  1694.   }
  1695.   if (node=(struct Node*)AllocVec(sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR))
  1696.   {
  1697.     node->ln_Name=DupStr(data);
  1698.     AddHead(N_ND->Last_Uploads,node);
  1699.     N_ND->Current_Last_Uploads++;
  1700.   }
  1701.   UpdateInfoWin();
  1702.   SendRequest(REQ_UPDATEINFO);
  1703. }
  1704.  
  1705.  
  1706. #define DSS_CONF 1
  1707. #define DSS_NODE 2
  1708. #define DSS_HBBS 3
  1709. #define DSS_ERR  4
  1710.  
  1711. V_BOOL DisplaySpecialScreen(char *ScreenName)
  1712. {
  1713.   char filename[BIG_STR];
  1714.   BOOL TriedAllLevels,Done=FALSE;
  1715.   struct Node *node;
  1716.  
  1717.   short whichdir=DSS_CONF;
  1718.   short CurrentAccess;
  1719.  
  1720.   do
  1721.   {
  1722.     filename[0]=0;
  1723.     if (N_ND->User.Valid)
  1724.     {
  1725.       TriedAllLevels=FALSE;
  1726.       CurrentAccess=WhatAccessNode(N_ND->User.CallData.Access);
  1727.     }
  1728.     else
  1729.     {
  1730.       CurrentAccess=-1;
  1731.     }
  1732.  
  1733.     do
  1734.     {
  1735.       switch(whichdir)
  1736.       {
  1737.         case DSS_CONF:
  1738.           if (N_ND->CurrentConf)
  1739.           {
  1740.             strcpy(filename,N_ND->CurrentConf->ConfPath);
  1741.           }
  1742.           break;
  1743.         case DSS_NODE:
  1744.           strcpy(filename,N_ND->NodeLocation);
  1745.           break;
  1746.         case DSS_HBBS:
  1747.           strcpy(filename,"HBBS:");
  1748.           break;
  1749.       }
  1750.  
  1751.       if (filename)
  1752.       {
  1753.         if (CurrentAccess<0) TriedAllLevels=TRUE;
  1754.  
  1755.         strcat(filename,DIRNAME_SCREENSSPECIAL);
  1756.         strcat(filename,ScreenName);
  1757.  
  1758.         if (N_ND->User.Valid && !TriedAllLevels)
  1759.         {
  1760.           // add access level _XX here..
  1761.  
  1762.           node=GetNode(BBSGlobal->AcsLevelList,CurrentAccess);
  1763.           CurrentAccess--;
  1764.           strcat(filename,"_");
  1765.           strcat(filename,node->ln_Name);
  1766.         }
  1767.         if (N_ND->User.Valid)
  1768.         {
  1769.           node=GetNode(BBSGlobal->LanguageExtn,N_ND->User.CallData.Language-1); //offset starts at 1
  1770.         }
  1771.         else
  1772.         {
  1773.           node=BBSGlobal->LanguageExtn->lh_Head;
  1774.         }
  1775.         strcat(filename,node->ln_Name);  // Change To Users Selected lanuage type
  1776.  
  1777.         Done=DisplayScreen(filename);
  1778.  
  1779.       } else TriedAllLevels=TRUE;
  1780.  
  1781.     } while (!TriedAllLevels && !Done);
  1782.  
  1783.  
  1784.     whichdir++;
  1785.  
  1786.   } while (! ((Done) || (whichdir==DSS_ERR)) );
  1787.   return(Done);
  1788. }
  1789.  
  1790. void SaveFileTags( void )
  1791. {
  1792.   struct CfgFileData *cfgfile;
  1793.   char tmpstr[BIG_STR];
  1794.   char optionstr[20];
  1795.   struct TaggedFile *filetagnode;
  1796.   int loop=0;
  1797.  
  1798.   sprintf(tmpstr,"HBBS:System/Data/Users/%d/TaggedFiles.CFG",N_ND->User.CallData.UserID);
  1799.  
  1800.   if (cfgfile=HBBS_CreateConfig(tmpstr))
  1801.   {
  1802.     // this item is ignored, it's just for the sysop's benefit so he can look at a file and see whose tags are in it..
  1803.  
  1804.     HBBS_AddCfgItem(cfgfile,"UserName",N_ND->User.CallData.Handle);
  1805.  
  1806.  
  1807.     for (filetagnode = (struct TaggedFile *)N_ND->TaggedFileList->lh_Head ; filetagnode->node.ln_Succ ; filetagnode =(struct TaggedFile*)filetagnode->node.ln_Succ)
  1808.     {
  1809.       loop++;
  1810.  
  1811.  
  1812.       if (filetagnode=(struct TaggedFile *)GetNode(N_ND->TaggedFileList,loop-1)) // get the node
  1813.       {
  1814.  
  1815.         sprintf(optionstr,"FileName_%d",loop);
  1816.         HBBS_AddCfgItem(cfgfile,optionstr,filetagnode->node.ln_Name);
  1817.  
  1818.         sprintf(optionstr,"WarezFile_%d",loop);
  1819.         HBBS_AddCfgItem(cfgfile,optionstr,filetagnode->WarezFile ? "YES" : "NO");
  1820.  
  1821.         sprintf(optionstr,"ConferenceNum_%d",loop);
  1822.         sprintf(tmpstr,"%d",filetagnode->ConferenceNum);
  1823.         HBBS_AddCfgItem(cfgfile,optionstr,tmpstr);
  1824.  
  1825.         sprintf(optionstr,"FileSize_%d",loop);
  1826.         sprintf(tmpstr,"%d",filetagnode->FileSize);
  1827.         HBBS_AddCfgItem(cfgfile,optionstr,tmpstr);
  1828.       }
  1829.     }
  1830.     HBBS_SaveConfig(cfgfile);
  1831.     HBBS_FlushConfig(cfgfile);
  1832.   }
  1833. }
  1834.  
  1835. void LoadFileTags( void )
  1836. {
  1837.   struct CfgFileData *cfgfile;
  1838.   char tmpstr[BIG_STR];
  1839.   char optionstr[20];
  1840.   char *strptr;
  1841.   struct TaggedFile *filetagnode;
  1842.   BOOL Error=FALSE;
  1843.   N_ND->TaggedFiles=0;
  1844.  
  1845.   // reinitialise list..
  1846.   NewList(N_ND->TaggedFileList);
  1847.  
  1848.   sprintf(tmpstr,"HBBS:System/Data/Users/%d/TaggedFiles.CFG",N_ND->User.CallData.UserID);
  1849.  
  1850.   if (cfgfile=HBBS_LoadConfig(tmpstr,LCFG_NONE))
  1851.   {
  1852.     do
  1853.     {
  1854.       Error=TRUE;
  1855.       strptr=NULL;
  1856.  
  1857.       sprintf(optionstr,"FileName_%d",N_ND->TaggedFiles+1);
  1858.       if (HBBS_GetSetting(cfgfile,(void *)&strptr,VTYPE_STRING,optionstr,OPT_SINGLE))
  1859.       {
  1860.         if (filetagnode=AllocVec(sizeof(struct TaggedFile),MEMF_PUBLIC))
  1861.         {
  1862.           N_ND->TaggedFiles++;
  1863.           filetagnode->node.ln_Name=strptr;
  1864.  
  1865.  
  1866.           sprintf(optionstr,"WarezFile_%d",N_ND->TaggedFiles);
  1867.           if (HBBS_GetSetting(cfgfile,(void *)&filetagnode->WarezFile,VTYPE_BOOL,optionstr,OPT_SINGLE))
  1868.           {
  1869.  
  1870.             sprintf(optionstr,"ConferenceNum_%d",N_ND->TaggedFiles);
  1871.             if (HBBS_GetSetting(cfgfile,(void *)&filetagnode->ConferenceNum,VTYPE_BIGNUM,optionstr,OPT_SINGLE))
  1872.             {
  1873.  
  1874.               sprintf(optionstr,"FileSize_%d",N_ND->TaggedFiles);
  1875.               if (HBBS_GetSetting(cfgfile,(void *)&filetagnode->FileSize,VTYPE_BIGNUM,optionstr,OPT_SINGLE))
  1876.               {
  1877.                 Error=FALSE;
  1878.                 AddTail(N_ND->TaggedFileList,(struct Node*) filetagnode);
  1879.               }
  1880.             }
  1881.           }
  1882.           if (Error)
  1883.           {
  1884.             FreeStr(strptr);
  1885.             FreeVec(filetagnode);
  1886.             N_ND->TaggedFiles--;
  1887.           }
  1888.         }
  1889.       }
  1890.     } while (Error==FALSE);
  1891.     HBBS_FlushConfig(cfgfile);
  1892.   }
  1893. }
  1894.  
  1895.  
  1896. void ResetVars( void )
  1897. {
  1898.   LONG loop;
  1899.   char tmpfilename[BIG_STR];
  1900.  
  1901.   for (loop=0;loop<LEN_ACTIONS;loop++)
  1902.   {
  1903.     N_ND->Actions[loop]=ACTC_NONE;
  1904.   }
  1905.   N_ND->Actions[LEN_ACTIONS]=0;
  1906.  
  1907.   N_ND->NodeFlags=NFLG_NONE;
  1908.   N_ND->User.Valid=FALSE;
  1909.   N_ND->Action[0]=0;
  1910.   N_ND->DoorReturn[0]=0;
  1911.   N_ND->CurrentLine[0]=0;
  1912.   N_ND->CurrentLineWrap[0]=0;
  1913.   N_ND->CurrentConf=NULL;
  1914.   N_ND->MaxDIZLines=N_ND->NodeSettings.MaxDIZLines;
  1915.   N_ND->User.FilesUploaded=0L;
  1916.   N_ND->User.FilesDownloaded=0L;
  1917.   N_ND->User.BytesUploaded=0L;
  1918.   N_ND->User.BytesDownloaded=0L;
  1919.   N_ND->User.PagesMade=0L;
  1920.   N_ND->User.NukedFiles=0L;
  1921.   N_ND->User.MsgsRead=0L;
  1922.   N_ND->User.MsgsWritten=0L;
  1923.   N_ND->DoorLogOverride=FALSE;
  1924.   HBBS_SetBBSCols();
  1925.   HBBS_SetBBSStrings();
  1926.  
  1927.   // remove file
  1928.   strcpy(tmpfilename,N_ND->NodeLocation);
  1929.   strcat(tmpfilename,"Work/SkippedFiles.TXT");
  1930.   DeleteFile(tmpfilename);
  1931. }
  1932.  
  1933. void FreeData( void )
  1934. {
  1935.   if (N_ND->User.Valid)
  1936.   {
  1937.     N_ND->User.NormalData.TimeUsed+=HBBS_TimeOnline();
  1938.     HBBS_SaveUserData(&N_ND->User.NormalData);
  1939.     SaveFileTags();
  1940.     FreeFileTags(N_ND);
  1941.   }
  1942.   N_ND->OnlineStatus=OS_OFFLINE;
  1943. }
  1944.  
  1945. void GoBBS( void )
  1946. {
  1947.   char tmpstr[1024],confstr[10],datestr[LEN_DATESTR],timestr[LEN_TIMESTR];
  1948.   V_BIGNUM confnum,loop,loop2;
  1949.   BOOL ReLogin=FALSE;
  1950.  
  1951.   do
  1952.   {
  1953.     ResetVars();
  1954.     PutText(str_CLS);
  1955.     PutText("\033[37;1m");
  1956.  
  1957.     sprintf(tmpstr,"HNode%dLoginType",N_ND->NodeNum);
  1958.  
  1959.     switch(N_ND->LoginType)
  1960.     {
  1961.       case LOGIN_LOCAL:
  1962.         ConWriteStr("-=LOCAL LOGIN=-\r\n");
  1963.         SetVar(tmpstr,"LOCAL",-1 ,GVF_GLOBAL_ONLY);
  1964.         break;
  1965.       case LOGIN_REMOTE:
  1966.         ConWriteStr("-=REMOTE LOGIN=-\r\n");
  1967.         SetVar(tmpstr,"REMOTE",-1 ,GVF_GLOBAL_ONLY);
  1968.         break;
  1969.     }
  1970.  
  1971.     sprintf(tmpstr,"***********[-CONNECTION ESTABLISHED-]***********[%s*", N_ND->LoginType==LOGIN_REMOTE ? "REMOTE]" : "LOCAL]*");
  1972.     HBBS_AddToCallersLog(tmpstr);
  1973.  
  1974.  
  1975.     PutText(ANSI_RESET);
  1976.  
  1977.     GoSystemDoor("FRONTEND",NULL);
  1978.     if (N_ND->OnlineStatus==OS_ONLINE)
  1979.     {
  1980.       // ok, check to see what the frontend door returned..
  1981.       strcpy(tmpstr,N_ND->DoorReturn);
  1982.  
  1983.       if (iposition("HACK",tmpstr)>=0)
  1984.       {
  1985.         sprintf(tmpstr,"Hack Attempt - %s",(N_ND->User.Valid ? N_ND->User.CallData.Handle : ""));
  1986.         HBBS_AddToCallersLog(tmpstr);
  1987.  
  1988.         // update list of PW Fails..
  1989.  
  1990.         if (N_ND->User.Valid)
  1991.         {
  1992.           Add_Last_PWFail(N_ND->User.CallData.Handle); // add to both...
  1993.           Add_Last_Caller(N_ND->User.CallData.Handle);
  1994.           N_ND->Actions[ACTN_HACK]=ACTC_HACK;
  1995.         }
  1996.  
  1997.       }
  1998.       else
  1999.       if (iposition("FAILED",tmpstr)>=0)
  2000.       {
  2001.         // do something.. (update calls log)
  2002.  
  2003.         sprintf(tmpstr,"Failed Login - %s",(N_ND->User.Valid ? N_ND->User.CallData.Handle : ""));
  2004.         HBBS_AddToCallersLog(tmpstr);
  2005.       }
  2006.       else
  2007.       if (iposition("LOGGEDIN",tmpstr)>=0)
  2008.       {
  2009.         N_ND->Actions[ACTN_CARRIERLOST]=ACTC_CARRIERLOST; // the LOGOUT door ('G') must set this to ACTC_NONE
  2010.  
  2011.         sprintf(tmpstr,"User logged in, Handle: %s Group: %s Speed: %s",N_ND->User.CallData.Handle,N_ND->User.CallData.Group,N_ND->ConnectBaud);
  2012.         HBBS_AddToCallersLog(tmpstr);
  2013.  
  2014.         HBBS_SetAccess();
  2015.  
  2016.         HBBS_SetWatchTitles();
  2017.         DOOR_UpdateNodeStatus(UPD_NAME);
  2018.         DOOR_UpdateNodeStatus(UPD_GROUP);
  2019.         Add_Last_Caller(N_ND->User.CallData.Handle);
  2020.  
  2021.         HBBS_GetDate(datestr);
  2022.         HBBS_GetTime(timestr);
  2023.  
  2024.         // update the users stats..
  2025.  
  2026.         HBBS_GetDateStr(tmpstr,N_ND->User.CallData.LastCalledDate);
  2027.         if (stricmp(tmpstr,datestr)!=0) // date last user called is different from today..
  2028.         {
  2029.           N_ND->User.CallData.TimeUsed=0;
  2030.           N_ND->User.NormalData.TimeUsed=0;
  2031.         }
  2032.  
  2033.         N_ND->User.NormalData.CallsMade++;
  2034.         N_ND->User.CallData.CallsMade++;
  2035.         N_ND->User.CallData.LastCalledDate=time(NULL);
  2036.         N_ND->User.NormalData.LastCalledDate=N_ND->User.CallData.LastCalledDate;
  2037.  
  2038.         // user logged in ok.
  2039.         sprintf(tmpstr,"HNode%dUser",N_ND->NodeNum);
  2040.         SetVar(tmpstr,N_ND->User.CallData.Handle,-1,GVF_GLOBAL_ONLY);
  2041.         LoadFileTags();
  2042.  
  2043.         if (stricmp(BBSGlobal->LastCalledDate,datestr)==0)
  2044.         {
  2045.           BBSGlobal->CallsToday++;
  2046.           N_ND->CallsToday++;
  2047.         }
  2048.         else
  2049.         {
  2050.           BBSGlobal->CallsToday=1;
  2051.           N_ND->CallsToday=1;
  2052.         }
  2053.  
  2054.         BBSGlobal->CallsEver++;
  2055.  
  2056.         strcpy(BBSGlobal->LastCalledDate,datestr);
  2057.         strcpy(BBSGlobal->LastCalledTime,timestr);
  2058.  
  2059.         strcpy(N_ND->LastCalledDate,datestr);
  2060.         strcpy(N_ND->LastCalledTime,timestr);
  2061.  
  2062.         HBBS_SaveCallsData();
  2063.         UpdatePrivateData();
  2064.  
  2065.  
  2066.         UpdateInfoWin(); // updates calls number in the window...
  2067.  
  2068.         GoSystemDoor("CheckUser","LOGON");
  2069.  
  2070.         if (stricmp(N_ND->DoorReturn,"LOGIN_DENIED")==0)
  2071.         {
  2072.           HBBS_AddToCallersLog("Login Denied by the Check User door!");
  2073.         }
  2074.         else
  2075.         {
  2076.  
  2077.           sprintf(tmpstr,"Speed_%s",N_ND->ConnectBaud);
  2078.           GoSystemDoor(tmpstr,NULL);
  2079.  
  2080.           if (N_ND->OnlineStatus==OS_ONLINE)
  2081.           {
  2082.  
  2083.             if (N_ND->User.CallData.Status!=USER_NEW)
  2084.             {
  2085.               DisplaySpecialScreen("LoginLogo");
  2086.             }
  2087.  
  2088.             if (N_ND->OnlineStatus==OS_ONLINE)
  2089.             {
  2090.  
  2091.               GoUserDoor("WALL",NULL);
  2092.  
  2093.               DisplaySpecialScreen("Bulletin");
  2094.  
  2095.               // check to see if user want's to keep tagged files from last visit
  2096.               // if he left with tagged files or lost carrier with files still tagged
  2097.  
  2098.               GoSystemDoor("CHECKTAGS",NULL);
  2099.  
  2100.               GoSystemDoor("MAILSCAN",NULL);
  2101.  
  2102.  
  2103.               sprintf(tmpstr,"HBBS:System/Data/Users/%d/%d.TXT",N_ND->User.CallData.UserID,N_ND->User.CallData.UserID);
  2104.               DisplayScreen(tmpstr);
  2105.  
  2106.               confnum=N_ND->User.CallData.LastConf;
  2107.               if (N_ND->User.CallData.PreferedConf) confnum=N_ND->User.CallData.PreferedConf;
  2108.               sprintf(confstr,"%d",confnum);
  2109.               GoSystemDoor("JOINCONF",confstr);
  2110.  
  2111.  
  2112.               GoSystemDoor("CMDPROMPT",NULL);
  2113.  
  2114.               // Normally a user is only logged off a) by the sysop pressing F10 or b) by
  2115.               // typing G at the CMDPROMPT door which then calls the logoff door. but if
  2116.               // there is a problem with starting the CMDPROMPT door then we'll have to force
  2117.               // logout the user by trying to run the LOGOUT door, which should logoff the
  2118.               // user
  2119.  
  2120.               if (N_ND->OnlineStatus==OS_ONLINE)
  2121.               {
  2122.                 GoUserDoor("G","SYSTEM");
  2123.               }
  2124.             }
  2125.           }
  2126.  
  2127.           // do the logoff scripts, but only if a user actually logged in..
  2128.           // and unlike /X this gets called even if you do a RL
  2129.           // so all your bulletins actually get updated!
  2130.  
  2131.           sprintf(tmpstr,"execute HBBS:Scripts/LogOff%ld.script %ld %ld",N_ND->NodeNum,N_ND->NodeNum,N_ND->User.CallData.UserID);
  2132.           HBBS_RunDOSCMD(tmpstr,FALSE);
  2133.  
  2134.           sprintf(tmpstr,"execute HBBS:Scripts/LogOff_Global.script %ld %ld",N_ND->NodeNum,N_ND->User.CallData.UserID);
  2135.           HBBS_RunDOSCMD(tmpstr,FALSE);
  2136.         }
  2137.       }
  2138.     }
  2139.     else
  2140.     {
  2141.       HBBS_AddToCallersLog("A user never logged in.  A carrier loss or timeout occured");
  2142.     }
  2143.     strcpy(tmpstr,"Actions: ");
  2144.     loop2=strlen(tmpstr);;
  2145.     for (loop=0;loop<LEN_ACTIONS;loop++)
  2146.     {
  2147.       if (N_ND->Actions[loop]!=ACTC_NONE)
  2148.       {
  2149.         tmpstr[loop2++]=N_ND->Actions[loop];
  2150.       }
  2151.     }
  2152.     tmpstr[loop2]=0;
  2153.     HBBS_AddToCallersLog(tmpstr);
  2154.  
  2155.     sprintf(tmpstr,"Totals: FU=%d FD=%d BU=%d BD=%d PM=%d NK=%d MR=%d MW=%d",
  2156.             N_ND->User.FilesUploaded,
  2157.             N_ND->User.FilesDownloaded,
  2158.             N_ND->User.BytesUploaded,
  2159.             N_ND->User.BytesDownloaded,
  2160.             N_ND->User.PagesMade,
  2161.             N_ND->User.NukedFiles,
  2162.             N_ND->User.MsgsRead,
  2163.             N_ND->User.MsgsWritten);
  2164.     HBBS_AddToCallersLog(tmpstr);
  2165.  
  2166.     if (N_ND->User.Valid)
  2167.     {
  2168.       sprintf(tmpstr,"Time Online: %ld",HBBS_TimeOnline());
  2169.     }
  2170.     HBBS_AddToCallersLog(tmpstr);
  2171.  
  2172.     HBBS_AddToCallersLog("End Of Session");
  2173.  
  2174.  
  2175.     FreeData();
  2176.     if (stricmp(N_ND->DoorReturn,"RELOGIN")==0)
  2177.     {
  2178.       ReLogin=TRUE;
  2179.       N_ND->OnlineStatus=OS_ONLINE;
  2180.       HBBS_AddToCallersLog("User is re-logging in!");
  2181.     }
  2182.     else
  2183.     {
  2184.       ReLogin=FALSE;
  2185.     }
  2186.  
  2187.   } while(ReLogin);
  2188.  
  2189.   if (!CarrierLost() && N_ND->LoginType==LOGIN_REMOTE) HangUp();
  2190. }
  2191.  
  2192. void ResetNodeVars( void )
  2193. {
  2194.   ResetVars();
  2195.   // this is called just before the await connect door is called..
  2196.   strcpy(N_ND->ConnectBaud,"--------");
  2197.   DOOR_UpdateNodeStatus(UPD_ACTION);
  2198.   DOOR_UpdateNodeStatus(UPD_CPSBAUD);
  2199.   HBBS_SetAccess(); // clear access levels
  2200. }
  2201.  
  2202. BOOL CheckModem( void )
  2203. {
  2204.   BOOL retval=TRUE,Done=FALSE;
  2205.   if (N_ND->SerOK)
  2206.   {
  2207.     do
  2208.     {
  2209.       SerReset();
  2210.       if (SerWriteStrWithTimeout("AT\n\r",5,0))
  2211.       {
  2212.         Delay(N_ND->NodeDevice.DelayBetweenCmds);
  2213.         Done=TRUE;
  2214.       }
  2215.       else
  2216.       {
  2217.         Done=((rtEZRequest("Modem Not Responding","Retry|Cancel",NULL,(struct TagItem *)&rttags,NULL)) ? FALSE : TRUE);
  2218.         if (Done) retval=FALSE;
  2219.       }
  2220.       SerReset();
  2221.     } while (!Done);
  2222.   }
  2223.   return(retval);
  2224. }
  2225.  
  2226. void AwaitConnect( void )
  2227. {
  2228.   BOOL Error=FALSE;
  2229.  
  2230.   ResetNodeVars();
  2231.  
  2232.   if ((N_ND->NodeSettings.UseDevice==FALSE) || ((N_ND->NodeDevice.NullModemCable==FALSE) && CheckModem()) || (N_ND->NodeDevice.NullModemCable==TRUE))
  2233.   {
  2234.     do
  2235.     {
  2236.       if (!N_ND->NodeDevice.NullModemCable) InitModem();
  2237.       N_ND->RunningAwait=TRUE;
  2238.       Error=!GoSystemDoor("AWAIT",NULL);                 // GoSys returns true if door loads OK
  2239.       N_ND->RunningAwait=FALSE;
  2240.  
  2241.       // if local login then put modem offhook so no-one else calls...
  2242.       if (N_ND->LoginType==LOGIN_LOCAL)
  2243.       {
  2244.         if (!N_ND->NodeDevice.NullModemCable || !N_ND->NodeSettings.UseDevice) OffHook();
  2245.         strcpy(N_ND->ConnectBaud,"LOCAL");
  2246.       }
  2247.  
  2248.       DOOR_UpdateNodeStatus(UPD_CPSBAUD);
  2249.       if (N_ND->LoginType!=LOGIN_NONE)
  2250.       {
  2251.         if (HistoryList=HBBS_CreateList())
  2252.         {
  2253.           HistoryItems=0;
  2254.  
  2255.           SendStatus(STAT_ONLINE);
  2256.           N_ND->OnlineStatus=OS_ONLINE;
  2257.  
  2258.           GoBBS();
  2259.  
  2260.           N_ND->LoginType=LOGIN_NONE;
  2261.  
  2262.           FreeStrList(HistoryList);
  2263.           HistoryList=NULL;
  2264.           HistoryItems=0;
  2265.  
  2266.           HBBS_FreeListNodes(N_ND->OLMList);
  2267.           N_ND->OLMCount=0;
  2268.  
  2269.           if (N_ND->NodeFlags & NFLG_OLMSWAITING) N_ND->NodeFlags-=NFLG_OLMSWAITING;
  2270.  
  2271.           SendStatus(STAT_READY);
  2272.         }
  2273.  
  2274.       }
  2275.       ResetNodeVars();
  2276.     } while (N_ND->RequestShutdown==FALSE && !Error);
  2277.     if (!N_ND->NodeDevice.NullModemCable && N_ND->NodeSettings.UseDevice) OffHook();
  2278.   } // else do error message
  2279.   if (Error)
  2280.   {
  2281.     HBBS_rterror("Error running door, \"Await\"");
  2282.   }
  2283. }
  2284.  
  2285. void HandleDoorIOMsg(struct DoorIOMsg *DMsg)
  2286. {
  2287.   DMsg->ReturnVal=0;
  2288.   switch(DMsg->Status)
  2289.   {
  2290.     case DOORIO_WRITECONSTR:
  2291.       ConWriteStr(DMsg->Data);
  2292.       break;
  2293.     case DOORIO_WRITECONDATA:
  2294.       ConWriteData(DMsg->Data,DMsg->DataLength);
  2295.       break;
  2296.     case DOORIO_WRITESERSTR:
  2297.       SerWriteStr(DMsg->Data);
  2298.       break;
  2299.     case DOORIO_WRITESERDATA:
  2300.       SerWriteData(DMsg->Data,DMsg->DataLength);
  2301.       break;
  2302.     case DOORIO_WRITESTR:
  2303.       PutText(DMsg->Data);
  2304.       break;
  2305.     case DOORIO_GETLINE:
  2306.       DMsg->ReturnVal=Get_Line(DMsg->Flags,DMsg->Data[0],DMsg->Num1,DMsg->Num2,DMsg->OptionStr);
  2307.       break;
  2308.     case DOORIO_CHANGECONSOLEMODE:
  2309.       HBBS_ChangeConsoleMode(DMsg->Num1);
  2310.       break;
  2311.     case DOORIO_SYSTEMDOOR:
  2312.       DMsg->ReturnVal=GoSystemDoor(DMsg->Data,DMsg->OptionStr);
  2313.       break;
  2314.     case DOORIO_USERDOOR:
  2315.       DMsg->ReturnVal=GoUserDoor(DMsg->Data,DMsg->OptionStr);
  2316.       break;
  2317.     case DOORIO_HANGUP:
  2318.       if (N_ND->LoginType==LOGIN_REMOTE) HangUp();
  2319.       N_ND->OnlineStatus=OS_OFFLINE;
  2320.       break;
  2321.     case DOORIO_DISPLAYSCREEN:
  2322.       DMsg->ReturnVal=DisplayScreen(DMsg->Data);
  2323.       break;
  2324.     case DOORIO_DISPLAYSPECIALSCREEN:
  2325.       DMsg->ReturnVal=DisplaySpecialScreen(DMsg->Data);
  2326.       break;
  2327.     case DOORIO_PAUSEPROMPT:
  2328.       PausePrompt(DMsg->Data,0);
  2329.       break;
  2330.     case DOORIO_CONTINUEPROMPT:
  2331.       DMsg->ReturnVal=ContinuePrompt(DMsg->Data,DMsg->Flags);
  2332.       break;
  2333.     case DOORIO_ADDLASTUPLOAD:
  2334.       Add_Last_Upload(DMsg->Data);
  2335.       break;
  2336.     case DOORIO_ADDLASTDOWNLOAD:
  2337.       Add_Last_Download(DMsg->Data);
  2338.       break;
  2339.     case DOORIO_MENUPROMPT:
  2340.       MenuPrompt(DMsg->Data,DMsg->OptionStr[0]);
  2341.       break;
  2342.     case DOORIO_CHECKRAW:
  2343.       DMsg->ReturnVal=CheckRaw(DMsg->Flags);
  2344.       break;
  2345.   }
  2346.   // a door message MAY be sent to the node without the control or other program
  2347.   // wanting to be told that the NODE has recived the message, all messages sent
  2348.   // that DONT want a reply WILL be freed..
  2349.  
  2350.   if (DMsg->message.mn_ReplyPort)
  2351.   {
  2352.     ReplyMsg((struct Message *)DMsg);
  2353.   }
  2354.   else
  2355.   {
  2356.     FreeVec(DMsg);
  2357.   }
  2358. }
  2359.